-- (i_left |**| (sign(i_right) *` (2.0 ^` (round(log2(abs(i_right))))))) +` i_bias

-- drop function if exists sm_sc.fv_gemm_power2_3ops(float[], float[], float[]);
create or replace function sm_sc.fv_gemm_power2_3ops
(
  i_left      float[]
, i_right     float[]
, i_bias      float[]   default null
)
returns float[]
as
$$
begin 
  if i_bias is null 
  then 
    return i_left |**| sm_sc.fv_arr_to_power2(i_right);
  else
    return (i_left |**| sm_sc.fv_arr_to_power2(i_right)) +` i_bias;
  end if;
end
$$
language plpgsql stable
parallel safe
;

-- select 
--   sm_sc.fv_gemm_power2_3ops
--   (
--     array[array[1, 2, 3], array[1, 2, 3]] :: float[],
--     array[array[1, 2], array[3, 1], array[2, 3]] :: float[]
--   )
-- select -- 2.328
--   sm_sc.fv_gemm_power2_3ops
--   (
--     sm_sc.fv_new_rand(array[70, 28 * 28]),
--     sm_sc.fv_new_rand(array[28 * 28, 25 * 6])
--   )
-- select -- 2.849
--   sm_sc.fv_gemm_power2_3ops
--   (
--     sm_sc.fv_new_rand(array[70, 10 * 10]),
--     sm_sc.fv_new_rand(array[10 * 10, 25 * 60])
--   )
-- select -- 0.990
--   sm_sc.fv_gemm_power2_3ops
--   (
--     sm_sc.fv_new_rand(array[70, 25 * 16]),
--     sm_sc.fv_new_rand(array[25 * 16, 120])
--   )
-- select -- 0.088
--   sm_sc.fv_gemm_power2_3ops
--   (
--     sm_sc.fv_new_rand(array[70, 120]),
--     sm_sc.fv_new_rand(array[120, 10])
--   )